(function(){
	var dh = Cf.DomHelper;
	
	Cf.Element = Cf.Class(Cf.Component, {
		constructor: function(el, config){
			Cf.put(this, config);
			this.dom = Cf.getDom(el);
			this.id = this.dom.id || Cf.seq();
			
			var events = [
			    // User Interface Event Types
			    'DOMActivate', 'DOMFocusIn', 'DOMFocusOut', 'focus',
			    'focusin', 'focusout', 'blur',
			    
			    // Basic Event Types
			    'load', 'unload', 'abort', 'error', 'select',
			    'change', 'submit', 'reset', 'resize', 'scroll',
			    
			    // Mouse Event Types
			    'click', 'dblclick', 'mousedown', 'mouseenter', 
			    'mouseleave', 'mousemove', 'mouseover', 'mouseout', 'mouseup',
			    
			    // Mouse Wheel Event Types
			    'mousewheel',
			    
			    // Wheel Event Types
			    'wheel',
			    
			    // Text Events Types
			    'textInput',
			    
			    // Keyboard Event Types
			    'keydown', 'keypress', 'keyup',
			    
			    // Composition Events Types
			    'compositionstart', 'compositionupdate', 'compositionend',
			    
			    // Mutation Events
			    'DOMSubtreeModified', 'DOMNodeInserted', 'DOMNodeRemoved', 
			    'DOMNodeInsertedIntoDocument', 'DOMNodeRemovedFromDocument', 
			    'DOMAttrModified', 'DOMCharacterDataModified',
			    
			    // Mutation Name Event Types
			    'DOMAttributeNameChanged', 'DOMElementNameChanged'
			];
			
			// add events
			this.addEvents.apply(this, events);

			// fire events
			var me = this,
				each;
			if(Cf.isIE){
				each = function(name, index, events){
					me.dom.attachEvent('on' + name, function(e){
						me.fireEvent(name, me, e);
					});
				};
			}else{
				each = function(name, index, events){
					me.dom.addEventListener(name, function(e){
						me.fireEvent(name, me, e);
					}, false);
				};
			}
			
			Cf.each(events, each, me);
			
			Cf.dom.Element.__parent.constructor.call(this, config);
		}
	
		,getDom: function(){
			return this.dom;	
		}
		
		,clear: function(){
			dh.clear(this.dom);
			return this;
		}
		
		,append: function(children){
			if(arguments.length > 1) children = arguments;
			dh.append(this.dom, children);
			return this;
		}
		
		,insert: function(index, children){
			if(arguments.length > 2) children = [].slice.call(arguments, 1);
			if(!Cf.isArray(children)) children = [children];
			
			for(var i = 0, len = children.length; i < len; ++i){
				dh.insertAt(index + i, this.dom, children[i]);	
			}
			
			return this;
		}
		
		,remove: function(selector){
			var doms = this.dom.querySelectorAll(selector);
			
			for(var i = 0, len = doms.length; i < len; ++i){
				this.dom.removeChild(doms[i]);	
			}
			
			return this;
		}
		
		,removeAt: function(/*arguments*/){
			var index;
			
			for(var i = 0, len = arguments.length; i < len; ++i){
				index = arguments[i];
				dh.remove(this.dom.children.item(index));
			}
			
			return this;
		}
		
		,wrap: function(wrap){
			dh.wrap(this.dom, wrap);
			return this;
		}
		
		,unwrap: function(){
			dh.unwrap(this.dom);
			return this;	
		}
		
		,update: function(o){
			dh.update(this.dom, o);
			return this;	
		}
		
		,appendTo: function(el){
			Cf.getDom(el).appendChild(this.dom);
			return this;
		}
		
		,replace: function(rep){
			dh.replace(this.dom, rep);
			return this;
		}
		
		,replaceWith: function(o){
			o = Cf.getDom(o);
			dh.replace(o, this.dom);
			return this;
		}
		
		,first: function(skipTextNode){
			var dom = this.dom.firstChild;
			if(skipTextNode && 3 == dom.nodeType) dom = dom.nextSibling;
			
			return dom? new Cf.dom.Element(dom) : null;
		}
		
		,last: function(skipTextNode){
			var dom = this.dom.lastChild;
			if(skipTextNode && 3 == dom.nodeType) dom = dom.previousSibling;
			
			return dom? new Cf.dom.Element(dom) : null;	
		}
		
		,getAt: function(index, skipTextNode){
			var dom = skipTextNode? this.dom.childNodes.item(index) : this.dom.children.item(index);
			return dom? new Cf.dom.Element(dom) : null;	
		}
		
		,getNext: function(skipTextNode){
			var dom = this.dom.nextSibling;
			if(skipTextNode && 3 == dom.nodeType) dom = dom.nextSibling;
			
			return dom? new Cf.dom.Element(dom) : null;	
		}
		
		,getPrev: function(){
			var dom = this.dom.previousSibling;
			if(skipTextNode && 3 == dom.nodeType) dom = dom.previousSibling;
			
			return dom? new Cf.dom.Element(dom) : null;		
		}
		
		,update: function(o){
			dh.update(this.dom, o);
			return this;
		}
		
		,getStyle: function(prop){
			var dom = this.dom;
			if(dom == document) return null;
			
			var v;
			if(v = dom.style[prop]) return v;
			
			var view = document.defaultView;
			if(view && view.getComputedStyle){
				if(v = getComputedStyle(dom, null)) return v[prop];
				return null;
			}
			
			if(v = dom.currentStyle) return v[prop];
			return null;
		}
		
		,setStyle: function(style, value){
			dh.setStyle(this.dom, style, value);
			return this;
		}
		
		,visible: function(visible){
			if(true === visible) visible = 'visible';
			if(false === visible) visible = 'hidden';
			this.dom.style.visibility = visible;
			return this;
		}
		
		,display: function(display){
			if(true === display) display = 'auto';
			if(false === display) display = 'none';
			this.dom.style.display = display;
			return this;
		}
		
		,hide: function(){
			this.visible(false);
			return this;
		}
		
		,show: function(){
			this.visible(true);
			return this;
		}
		
		,hasClass: function(name){
			var c = this.dom.className;
			if(!c) return false;
			if(name === c) return true;
			
			var regex = new RegExp(name + ' | ' + name +  '| ' + name + ' ');
			return regex.test(c);
		}
		
		,getClass: function(returnString){
			return dh.getClass(this.dom, returnString);
		}
		
		,addClass: function(c){
			dh.addClass(this.dom, c);
			return this;
		}
		
		,removeClass: function(c){
			dh.removeClass(this.dom, c);
			return this;
		}
		
		,focus: function(delay){
			var me = this;
			
			try{
				delay? (function(){
					me.dom.focus();
				}).delay(delay)() : me.dom.focus();
				
			}catch(e){}
			return this;
		}
		
		,getAttr: function(name){
			return this.dom.getAttribute(name);
		}
		
		,getPadding: function(side){
			var ret = 0, s;
				
			for(var i = 0; i < side.length; ++i){
				ret += (s = this.getStyle('padding' + mapSide[side[i]]).match(/\d+/))? parseInt(s[0]) : 0;
			}

			return ret;
		}
		
		,getBorderWidth: function(side){
			var ret = 0 ,s;
				
			for(var i = 0; i < side.length; ++i){
				ret += (s = this.getStyle('border' + mapSide[side[i]] + 'Width').match(/\d+/))? parseInt(s[0]) : 0;
			}

			return ret;
		}
		
		,getMargin: function(side){
			var ret = 0, s;
				
			for(var i = 0; i < side.length; ++i){
				ret += (s = this.getStyle('margin' + mapSide[side[i]]).match(/\d+/))? parseInt(s[0]) : 0;
			}

			return ret;
		}
		
		,getWidth: function(offset){
			var w = this.getStyle('width').match(/\d+/);
			w = w? parseInt(w[0]) : 0;
			if(!offset) return w;
			
			for(var i = 0; i < offset.length; ++i){
				w += this['get' + mapOffset[offset[i]]]('lr');
			}
			return w;
		}
		
		,getHeight: function(offset){
			var h = this.getStyle('height').match(/\d+/);
			h = h? parseInt(h[0]) : 0;
			if(!offset) return h;
			
			for(var i = 0; i < offset.length; ++i){
				h += this['get' + mapOffset[offset[i]]]('tb');
			}
			return h;
		}
		
		,getSize: function(offset){
			return this.getWidth() + this.getHeight();
		}
		
		,setWidth: function(w, offset){
			if($$.isNumber(w)){
				if(offset){
					for(var i = 0; i < offset.length; ++i){
						w -= this['get' + mapOffset[offset[i]]]('lr');
					}
				}
				if(w < 0) w = 0;
				w = w + 'px';
			}
			return this.setStyle({width: w});
		}
		
		,setHeight: function(h, offset){
			if($$.isNumber(h)){
				if(offset){
					for(var i = 0; i < offset.length; ++i){
						h -= this['get' + mapOffset[offset[i]]]('tb');
					}
				}
				if(h < 0) h = 0;
				h = h + 'px';
			}
			return this.setStyle({height: h});
		}
		
		,setSize: function(w, h, offset){
			return this.setWidth(w, offset).setHeight(h, offset);
		}
		
		,setX: function(x){
			x = typeof x == 'number'? x + 'px' : x;
			return this.setStyle({left: x});
		}
		
		,setY: function(y){
			y = typeof y == 'number'? y + 'px' : y;
			return this.setStyle({top: y});
		}
		
		,setXY: function(x, y){
			if(!y) y = x;
			return this.setX(x).setY(y);
		}
		
		,getX: function(){
			return this.dom.offsetLeft;
		}
		
		,getY: function(){
			return this.dom.offsetTop;
		}
		
		,getXY: function(){
			return [this.getX(), this.getY()];
		}
		
		,wrap: function(wrap, returnDom){
			wrap = dh.wrap(this.dom, wrap);
			return returnDom? wrap : new Cf.dom.Element(wrap);
		}
		
		,unwrap: function(){
			dh.unwrap(this.dom);
			return this;
		}
		
		,destroy: function(){
			dh.remove(this.dom);	
		}
		
		,toHTML: function(){
			var html = this.wrap({}, true).innerHTML;
			this.unWrap();
			return html;
		}
		
		,setOpacity: function(o){
			var me = this
				,s = me.dom.style;
			
			if (Cf.isIE) {
                s.zoom = 1;
                s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
                           (opacity == 1 ? "" : " alpha(opacity=" + opacity * 100 + ")");
            } else {
                s.opacity = o;
            }
				
			return this;
		}
	});
})();